package redis_lock

import (
	"context"
	"github.com/google/uuid"
	"github.com/redis/go-redis/v9"
	"github.com/zeromicro/go-zero/core/logx"
	"log"
	"sync"
	"time"
)

var (
	idStatusMap = make(map[string]IDStatus)
	mu          sync.Mutex
)

type Redis struct {
	client redis.Client
}
type IDStatus struct {
	UID    string
	Status bool
}

func (r *Redis) SetNum(f func()) {
	// 标记
	uuId := uuid.New()
	uid := uuId.String()
	var result int64
	var err error
	lockBool := false
	status, found := getStatus(uid)
	if status == true && found == true {
		lockBool = true
	} else {
		result, err = r.client.HSet(context.Background(), "lock", uid, 3*time.Second).Result()
		if err != nil {
			logx.Error(err)
			return
			//panic(err)
		}
	}
	if result == 1 {
		// 拿到锁了
		//go func() {
		//	for {
		//		time.Sleep(3 * time.Second)
		//		// 使用脚本或 Lua 来确保只有持有锁的客户端能续期
		//		// 这里为了简化，我们直接调用 Expire，但在生产环境中需要更严格的检查
		//		err := r.client.Expire(context.Background(), "lock", 3*time.Second).Err()
		//		if err != nil {
		//			// 如果锁不存在或其他错误，则退出续期循环
		//			// 注意：在实际应用中，这里可能需要更复杂的错误处理
		//			logx.Errorf("Failed to renew lock: %v", err)
		//			break
		//		}
		//		fmt.Println("Lock renewed successfully")
		//	}
		//}()
		f()
		// 判断是否是自己的锁
		// 执行完删除锁
		luaScript := "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"
		_, err = r.client.Eval(context.Background(), luaScript, []string{"lock"}, []interface{}{uid}).Result()
		if err != nil {
			log.Fatalf("Failed to execute Lua script: %v", err)
		}

	} else {

		// 没有拿到锁递归
		for lockBool {
			time.Sleep(50 * time.Millisecond)
			result, err = r.client.HSet(context.Background(), "lock", uid, 3*time.Second).Result()
			if err != nil {
				logx.Error(err)
				return
				//panic(err)
			}
			if result == 1 {
				idStatusMap[uid] = IDStatus{UID: uid, Status: true}
				break
			}
		}
		r.SetNum(f)
	}

}

// 设置标识符的状态
func setStatus(id string, status bool) {
	mu.Lock()
	defer mu.Unlock()
	idStatusMap[id] = IDStatus{UID: id, Status: status}
}

// 获取标识符的状态
func getStatus(id string) (bool, bool) { // 第二个返回值表示是否找到了该 ID
	mu.Lock()
	defer mu.Unlock()
	status, found := idStatusMap[id]
	return status.Status, found
}
